home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / _archvrs / unix / tcx-1_0.lha / tcx-1.0 / tcx.c < prev    next >
C/C++ Source or Header  |  1993-03-30  |  7KB  |  271 lines

  1. /* tcx.c, Version 1.0, 25/3/1993 by Stewart Forster */
  2.  
  3. /************************************************************************/
  4. /*   Copyright (C) 1993 Stewart Forster                    */
  5. /*  This program is free software; you can redistribute it and/or modify*/
  6. /*  it under the terms of the GNU General Public License as published by*/
  7. /*  the Free Software Foundation; either version 2, or (at your option) */
  8. /*  any later version.                            */
  9. /*                                    */
  10. /*  This program is distributed in the hope that it will be useful,    */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  13. /*  GNU General Public License for more details.            */
  14. /*                                    */
  15. /*  You should have received a copy of the GNU General Public License    */
  16. /*  along with this program; if not, write to the Free Software        */
  17. /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  18. /************************************************************************/
  19.  
  20.  
  21. #include    "config.h"
  22.  
  23. extern    int    errno;
  24.  
  25. int    main(int, char *[]);
  26. int    is_tcx(int);
  27. int    doencode(int, int);
  28.  
  29. int
  30. main(int argc, char *argv[])
  31. {
  32. struct    stat    dostat;
  33. char    *s;
  34. int    perms;
  35. int    infd, outfd;
  36. char    tofile[MAXPATHLEN];
  37. char    header[MAXHEADERSIZE];
  38. struct    flock    lck;
  39. unsigned char c;
  40.  
  41.     /* Check to make sure we have an argument */
  42.  
  43.     if(argc < 2)
  44.     {
  45.         (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  46.         exit(-1);
  47.     }
  48.  
  49.     /* Try to lstat first argument. If cannot, quit */
  50.  
  51.     if(lstat(argv[1], &dostat) < 0)
  52.     {
  53.         perror(argv[1]);
  54.         exit(-1);
  55.     }
  56.  
  57.     /* Make sure it's a regular file. If not, quit! */
  58.  
  59.     if(!(dostat.st_mode & S_IFREG)||((dostat.st_mode & S_IFMT) == S_IFLNK))
  60.     {
  61.         (void)fprintf(stderr, "Error: %s is not a regular file\n", argv[1]);
  62.         exit(-1);
  63.     }
  64.  
  65.     /* Check permissions on file, must not be setuid or setgid */
  66.     /* Then check to see if it's an executable */
  67.  
  68.     if(dostat.st_mode & (S_ISUID | S_ISGID))
  69.     {
  70.         (void)fprintf(stderr, "Error: Cannot compress setuid or setgid programs.\n");
  71.         exit(-1);
  72.     }
  73.  
  74.     if(! (dostat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
  75.     {
  76.         (void)fprintf(stderr, "File does have any execute bits set. Aborting.\n");
  77.         exit(-1);
  78.     }
  79.  
  80.     /* Now open file we are compressing for reading. Quit if can't. */
  81.  
  82.     if((infd = open(argv[1], O_RDONLY)) < 0)
  83.     {
  84.         perror(argv[1]);
  85.         exit(-1);
  86.     }
  87.  
  88.     /* Check to make sure file is not already tcx'ed */
  89.  
  90.     if(is_tcx(infd))
  91.     {
  92.         (void)fprintf(stderr, "%s is already in tcx format!\n", argv[1]);
  93.         exit(0);
  94.     }
  95.  
  96.     if(lseek(infd, 0, SEEK_SET) < 0)
  97.     {
  98.         perror("lseek");
  99.         exit(-1);
  100.     }
  101.  
  102.     /* Open generation file, and try to mimic permissions */
  103.     /* If cannot, warn user and quit */
  104.  
  105.     if(strrchr(argv[1], '/') == NULL)
  106.         (void)sprintf(tofile, ".tcx.%s", argv[1]);
  107.     else
  108.     {
  109.         (void)strcpy(tofile, argv[1]);
  110.         s = strrchr(tofile, '/');
  111.         *s = '\0';
  112.         (void)strcat(tofile, "/.tcx.");
  113.         s = strrchr(argv[1], '/');
  114.         s++;
  115.         (void)strcat(tofile, s);
  116.     }
  117.  
  118.     if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY)) < 0)
  119.     {
  120.         if(errno != EEXIST)
  121.         {
  122.             perror(tofile);
  123.             exit(-1);
  124.         }
  125.         if((outfd = open(tofile, O_WRONLY)) < 0)
  126.         {
  127.             perror(tofile);
  128.             exit(-1);
  129.         }
  130.     }
  131.  
  132.     /* Attempt to lock tofile.  If can't then assume someone else */
  133.     /* is in the process of packing this file, so quit.  If can */
  134.     /* then tofile must be bogus (result of crash or whatever) so */
  135.     /* we can just write over it */
  136.  
  137.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  138.     if(fcntl(outfd, F_SETLK, &lck) < 0)
  139.         exit(-1);
  140.  
  141.     if(ftruncate(outfd, 0) < 0)
  142.     {
  143.         perror("ftruncate");
  144.         exit(-1);
  145.     }
  146.     
  147.     perms = (dostat.st_mode & 0777);
  148.     if(perms & S_IXUSR) perms |= S_IRUSR;
  149.     if(perms & S_IXGRP) perms |= S_IRGRP;
  150.     if(perms & S_IXOTH) perms |= S_IROTH;
  151.     perms |= S_IWUSR;
  152.     if(chmod(tofile, perms) < 0)
  153.     {
  154.         (void)fprintf(stderr, "Cannot set proper permissions on scratch file %s\n", tofile);
  155.         (void)close(infd);
  156.         (void)close(outfd);
  157.         if(unlink(tofile) < 0)
  158.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  159.         exit(-1);
  160.     }
  161.  
  162.     if(chown(tofile, dostat.st_uid, dostat.st_gid) < 0)
  163.     {
  164.         (void)fprintf(stderr, "Cannot set proper ownership on scratch file\n");
  165.         (void)close(infd);
  166.         (void)close(outfd);
  167.         if(unlink(tofile) < 0)
  168.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  169.         exit(-1);
  170.     }
  171.  
  172.     /* Spit out header and start encoding executable */
  173.  
  174.     (void)sprintf(header, "#!%s\n", PATHUNTCX);
  175.     if(write(outfd, header, strlen(header)) < 0) { (void)perror("write"); exit(-1); }
  176.  
  177.     c = 0;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  178.     c = 76;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  179.     c = 193; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  180.     c = 13;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  181.     c = 138; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  182.  
  183.     if(doencode(infd, outfd) != 0)
  184.     {
  185.         (void)fprintf(stderr, "Compression failed\n");
  186.         if(unlink(tofile) < 0)
  187.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  188.         exit(-1);
  189.     }
  190.  
  191.     (void)close(infd);
  192.  
  193.     if((infd = open(argv[1], O_WRONLY)) <= 0)
  194.     {
  195.         perror(argv[1]);
  196.         if(unlink(tofile) < 0)
  197.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  198.         exit(-1);
  199.     }
  200.  
  201.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  202.     if(fcntl(infd, F_SETLK, &lck) < 0)
  203.     {
  204.         if(unlink(tofile) < 0)
  205.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  206.         exit(-1);
  207.     }
  208.  
  209.     /* Rename() compressed version to original */
  210.  
  211.     if(rename(tofile, argv[1]) < 0)
  212.     {
  213.         perror(argv[1]);
  214.         if(unlink(tofile) < 0)
  215.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  216.         exit(-1);
  217.     }
  218.  
  219.     /* Close files and hence locks */
  220.  
  221.     (void)close(infd);
  222.     (void)close(outfd);
  223.  
  224.     /* All done! Bye, bye. */
  225.  
  226.     return(0);
  227. }
  228.  
  229.  
  230. int
  231. is_tcx(int fd)
  232. {
  233. int     i;
  234. unsigned char   c;
  235.  
  236.         for(i = 0; i < MAXHEADERSIZE; i++)
  237.                 if(read(fd, &c, 1) < 1 || c == 0)
  238.                         break;
  239.         if((i >= MAXHEADERSIZE) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  240.             || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  241.                 return 0;
  242.         return 1;
  243. } /* is_tcx */
  244.  
  245.  
  246. int
  247. doencode(int infd, int outfd)
  248. {
  249. int    pid;
  250. union    wait    status;
  251.  
  252.     pid = fork();
  253.     if(pid < 0) return -1;
  254.     if(pid == 0)
  255.     {
  256.         if(dup2(infd, 0) < 0)    exit(-1);
  257.         (void)close(infd);    /* Attach infd to stdin */
  258.         if(dup2(outfd, 1) < 0)    exit(-1);
  259.         (void)close(outfd);    /* Attach outfd to stdout */
  260. #ifdef PACKEROPTS
  261.         (void)execl(PATHPACKER, "packer", PACKEROPTS, (char *)0);
  262. #else
  263.         (void)execl(PATHPACKER, "packer", (char *)0);
  264. #endif
  265.         exit(-1);
  266.     }
  267.     else
  268.         pid = wait(&status);
  269.     return WEXITSTATUS(status);
  270. } /* doencode */
  271.